﻿using System;
using System.Globalization;
using System.IO;
using System.Threading;

namespace SharpDepend
{
    public static class Log
    {
        public static event Action<string> OnDebug;

        public static event Action<string> OnError;

        public static event Action<string> OnWarning;

        public static string WriteToFile;

        public static void Debug(object instance, string message)
        {
            OnDebug?.Invoke(message);
            LogToFile(message);
        }

        public static void Error(object instance, string message)
        {
            OnError?.Invoke(message);
            LogToFile(message);
        }

        public static void Error(object instance, Exception exception)
        {
            OnError?.Invoke(exception.Message);
            WriteException(instance, exception, 0);
        }

        private static void WriteException(object instance, Exception exception, int innerExceptionStep)
        {
            lock (WriteToFile)
            {
                LogToFile(DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss.fff", CultureInfo.InvariantCulture) + ": ", false);

                if (innerExceptionStep == 0)
                {
                    LogToFile("==" + exception.GetType().Name + "==");
                }
                else
                {
                    LogToFile("== InnerException (" + innerExceptionStep + ") " + exception.GetType().Name + "==");
                }
                
                LogToFile("From instance:");
                LogToFile(instance == null ? "NULL" : instance.ToString());
                LogToFile("Message:");
                LogToFile(exception.Message);
                LogToFile("StackTrace:");
                LogToFile(exception.StackTrace);
                LogToFile("InnerException:");
                if (exception.InnerException != null)
                {
                    WriteException(instance, exception.InnerException, ++innerExceptionStep);
                }
                else
                {
                    LogToFile("NULL");
                }
            }
        }

        public static void Warning(object instance, string message)
        {
            OnWarning?.Invoke(message);
            LogToFile(message);
        }

        public static void Assert(bool condition, string message)
        {
            //System.Diagnostics.Debug.Assert(condition, message);
        }

        private static void LogToFile(string message, bool newLine = true)
        {
            if (!string.IsNullOrWhiteSpace(WriteToFile))
            {
                Stream stream = null;
                if(!Manager.FileManager.PathExist(WriteToFile, false))
                {
                    stream = Manager.FileManager.CreateFile(WriteToFile);
                }
                else
                {
                    stream = Manager.FileManager.OpenFile(WriteToFile);
                    stream.Position = stream.Length;
                }

                using (StreamWriter writer = new StreamWriter(stream))
                {
                    if (newLine)
                    {
                        writer.WriteLine(message);
                    }
                    else
                    {
                        writer.Write(message);
                    }
                }
            }
        }
    }
}
